#ifndef G_BYTE_UTILS_H
#define G_BYTE_UTILS_H
/*
gbyteutils.h
18/05/2014
psycommando@gmail.com

Description:
A bunch of simple tools for doing common tasks when manipulating bytes.
*/
#include <vector>
#include <cstdint>

namespace g { namespace byteutils {

    typedef uint8_t byte;

	//Consts
    static const unsigned int SZ_INT32          = 0x4;
    static const unsigned int SZ_INT16          = 0x2;
	static const unsigned int MASK_UINT32_BYTE0 = 0X000000FF,  //0000 0000 - 0000 0000 - 0000 0000 - 1111 1111
							  MASK_UINT32_BYTE1 = 0x0000FF00,  //0000 0000 - 0000 0000 - 1111 1111 - 0000 0000
							  MASK_UINT32_BYTE2 = 0x00FF0000,  //0000 0000 - 1111 1111 - 0000 0000 - 0000 0000
							  MASK_UINT32_BYTE3 = 0xFF000000;  //1111 1111 - 0000 0000 - 0000 0000 - 0000 0000


    template< bool _BoolExpr, class T, T _OPTION_A, T _OPTION_B>
        struct conditional_value
        {
            static const T value = (_BoolExpr)? _OPTION_A : _OPTION_B;
        };


    template<unsigned long long _Exponent>
        struct do_exponent_of_2_
        {
            static const unsigned long long value = do_exponent_of_2_< (_Exponent - 1u) >::value * 2;
        };

    template<>
        struct do_exponent_of_2_<0>
        {
            static const unsigned long long value = 1;
        };

	/*
		Name: LittleEndianToBigEndianUInt32
		In:
			- unsigned int val : bytes to convert from little to big endian.
		Out:
			- unsigned int	   : bytes converted to big endian.

		Description: 
		This simply swap the order of bytes from a little endian order to a big endian order.
		It works on a per byte level.

	*/
	unsigned int LittleEndianToBigEndianUInt32( unsigned int val );


	/*
		Name: ByteBuffToUnsignedInt
		In:
			- const char buff[] : bytes to assemble into an unsigned 32bits integer.
		Out:
			- unsigned int	    : an unsigned integer assembled from the bytes passed in the buffer.

		Description: 
		Assembles the bytes into an unsigned int, and applies masks to clean up any weirdness caused by bitshifts!

	*/
	unsigned int ByteBuffToUnsignedInt( const byte buff[] );
    void UnsignedIntToByteBuff( unsigned int value, byte buff[] );


    /*
        Name: ByteBuffToInt16
        In:
            - const char buff[] : bytes to assemble into an int16
        Out:
            - unsigned short    : the assembled int16 from the byte buffer.

        Description:
        Assembles the bytes in the buffer into an int16, applying masks to clean it up..
    */
    unsigned short ByteBuffToInt16( const byte buff[] );
    void Int16ToByteBuff( unsigned short value, byte outbuff[] );

    /*
        Name: readInt32FromByteVector
        In:
            - vector<char>::const_iterator : vector to read the bytes from.
        Out:
            - unsigned int                 : the assembled int32 from the byte vector.

        Description:
        Assembles the 4 bytes after the iterator's position, into an int32..
    */
    unsigned int readInt32FromByteVector( std::vector<byte>::const_iterator first );

    /*
        Name: readInt16FromByteVector
        In:
            - vector<char>::const_iterator : vector to read the bytes from.
        Out:
            - unsigned int                 : the assembled int16 from the byte vector.

        Description:
        Assembles the 2 bytes after the iterator's position, into an int16..
    */
    unsigned short readInt16FromByteVector( std::vector<byte>::const_iterator first );

//===============================================================================
//								Utility
//===============================================================================
    inline unsigned int GetNextInt32DivisibleBy16( unsigned int baseoffset )
    {
        if( (baseoffset % 16) != 0 )
        {
            return ( ( baseoffset / 16 ) + 1 ) * 16;
        }
        return baseoffset;
    }

}; };

#endif